package com.lwq.imserver.util;

import com.alibaba.fastjson.JSON;
import com.lwq.imserver.model.ChatRoom;
import com.lwq.imserver.model.SendBody;
import com.lwq.imserver.model.TransferModel;
import com.lwq.imserver.model.system.SysUser;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * Description:
 * Author: LiuWenQing
 * Datetime: 2022/1/17 16:48
 */
@Slf4j
public class WebSocketUtil {

    private static Map<String, Channel> channelMap = new ConcurrentHashMap<>(10000);

    public static List<SysUser> userList = new ArrayList<>();

    public static List<ChatRoom> chatRoomList = new ArrayList<>();

    public static Map<String, Channel> getChannelMap() {
        return channelMap;
    }


    public static String getUserName(Channel channel) {
        Set<Map.Entry<String, Channel>> entries = channelMap.entrySet();
        for (Map.Entry<String, Channel> map : entries){
            if(map.getValue().id().equals(channel.id())){
                return userList.stream().filter(e->e.getId().equals(map.getKey())).findAny().isPresent()?
                        userList.stream().filter(e->e.getId().equals(map.getKey())).collect(Collectors.toList()).get(0).getUserName(): "";
            }
        }
        return "";
    }

    public static String getToken(HttpRequest msg) {
        String uri = msg.getUri();
        int index = uri.lastIndexOf("/");
        if (index < 0) {
            return null;
        }
        return uri.substring(index+1);
    }

    public static void singleCast(SendBody sendBody){
        Channel channel = channelMap.get(sendBody.getReceive());
        if(channel != null && channel.isOpen()){
            if(channel.isWritable()){
                channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody)));
            }else{
                try{
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody))).sync();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }

    public static void broadCast(SendBody sendBody){
        if(sendBody.getType().equals(TransferModel.SEND) && !sendBody.getRoomId().equals("1")){
            for(Object next: channelMap.entrySet().stream().filter(e-> {
                if(chatRoomList.stream()
                        .anyMatch(i-> i.getId().equals(sendBody.getRoomId())
                                && i.getMembers().stream().map(a->a.getId())
                                .collect(Collectors.toList()).contains(e.getKey()))){
                    return true;
                }
                return false;
            }).collect(Collectors.toSet())){
                Map.Entry<String, Channel> tempNext = (Map.Entry<String, Channel>)next;
                Channel channel = tempNext.getValue();
                if (channel != null && channel.isOpen()) {
                    if (channel.isWritable()) {
                        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody)));
                    } else {
                        try {
                            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody))).sync();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }else{
            for (Map.Entry<String, Channel> next : channelMap.entrySet()) {
                Channel channel = next.getValue();
                if (channel != null && channel.isOpen()) {
                    if (channel.isWritable()) {
                        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody)));
                    } else {
                        try {
                            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody))).sync();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public static void broadCastRemoveRoom(List<String> ids,String fromId,ChatRoom chatRoom){
        SendBody sendBody = new SendBody();
        sendBody.setType(TransferModel.REMOVEROOM);
        sendBody.setTimestamp(System.currentTimeMillis());
        sendBody.setFromName(userList.stream().filter(e->e.getId().equals(fromId)).findAny().get().getUserName());
        sendBody.setChatRoom(chatRoom);
        for(Map.Entry<String, Channel> next : channelMap.entrySet()) {
            if(!ids.contains(next.getKey())){
                continue;
            }
            Channel channel = next.getValue();
            if (channel != null && channel.isOpen()) {
                if (channel.isWritable()) {
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody)));
                } else {
                    try {
                        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody))).sync();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void broadCastAddRoom(ChatRoom chatRoom){
        SendBody sendBody = new SendBody();
        sendBody.setType(TransferModel.ADDROOM);
        sendBody.setTimestamp(System.currentTimeMillis());
        sendBody.setChatRoom(chatRoom);
        for(Map.Entry<String, Channel> next : channelMap.entrySet()){
            if(!chatRoom.getMembers().stream().map(e->e.getId()).collect(Collectors.toList()).contains(next.getKey())){
                continue;
            }
            Channel channel = next.getValue();
            if (channel != null && channel.isOpen()) {
                if (channel.isWritable()) {
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody)));
                } else {
                    try {
                        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody))).sync();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void broadCast(SendBody sendBody,String userId){
        for (Map.Entry<String, Channel> next : channelMap.entrySet()) {
            if(next.getKey().contains(userId)) continue;
            Channel channel = next.getValue();
            if (channel != null && channel.isOpen()) {
                if (channel.isWritable()) {
                    channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody)));
                } else {
                    try {
                        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(sendBody))).sync();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void removeChannelByChannel(Channel channel) {
        Set<Map.Entry<String, Channel>> entries = channelMap.entrySet();
        Iterator<Map.Entry<String, Channel>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Channel> next = iterator.next();
            Channel value = next.getValue();
            if (value.id().equals(channel.id())) {
                iterator.remove();
            }
        }
    }

    public static void removeChannelByKey(String key){
        Set<Map.Entry<String, Channel>> entries = channelMap.entrySet();
        Iterator<Map.Entry<String, Channel>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Channel> next = iterator.next();
            String tempKey = next.getKey();
            if (tempKey.equals(key)) {
                iterator.remove();
            }
        }
    }

}
